import time

from ShuDuLine import ShuDuLine
import math
import numpy as np
import matplotlib.pyplot as plt


def pad_array_to_length(arr, target_length, pad_value=0):
    # 计算需要填充的元素个数
    pad_width = target_length - len(arr)
    # 如果目标长度小于原数组长度，则不做任何操作
    if pad_width <= 0:
        return arr
    else:
        # 使用numpy.pad进行填充
        return np.pad(arr, (0, pad_width), 'constant', constant_values=pad_value)


def checkLine(line, check, force):
    t = []
    l = 0

    for i in range(0, len(line)):
        p = line[i]
        if p == '1':
            l += 1
            if (i == len(line) - 1) and l:
                t.append(l)
        else:
            if l:
                t.append(l)
            l = 0

    if not t:
        return True

    if line[-1] == '0':
        if len(t) >= len(check):
            force = True

    if force:
        return t == check

    if len(t) > len(check):
        return False

    for k, v in enumerate(t):
        if v > check[k]:
            return False
    return True


def repeat_string(s, n):
    return s * n


class ShuDu:
    def __init__(self, x, y):
        self.ax = None
        self.fig = None
        #####
        self.x = x
        self.y = y
        self.tmpList = []
        self.resList = []
        self.beginAt = ''
        self.endAt = ''
        self.size = len(x)
        self.beginAt = time.time()
        self.times = 0
        self.type = ''
        self.canPlt = False
        self.doing = True
        self.data = []

    def pltInit(self):
        self.fig = plt.figure(num=1)
        self.ax = self.fig.add_subplot(111)

    def begin(self):
        dx = dy = 0

        for i in self.x:
            dx += sum(i)
        for i in self.y:
            dy += sum(i)
        if dx != dy:
            print('sum error')
            return

        self.getTmpList()

        if self.canPlt:
            self.pltInit()
        self.todo(0)

    def getTmpList(self):

        # self.shortList()

        for i in self.y:
            t = ShuDuLine(self.size, i)
            self.tmpList.append(t.getLine())

    def shortList(self):
        ClistX = []
        for i in self.x:
            t = ShuDuLine(self.size, i)
            ClistX.append(len(t.getLine()))

        ClistY = []
        for i in self.y:
            t = ShuDuLine(self.size, i)
            ClistY.append(len(t.getLine()))

        half = math.ceil(self.size / 2)

        halfXT = sum(ClistX[:half])
        halfXF = sum(ClistX[half:])
        halfYT = sum(ClistY[:half])
        halfYF = sum(ClistY[half:])

        print('XT::'+str(halfXT))
        print('XF::'+str(halfXF))
        print('YT::'+str(halfYT))
        print('YF::'+str(halfYF))

        TMin = min(halfXT, halfXF, halfYT, halfYF)

        if TMin == halfYF:
            self.y = self.y[::-1]
            x1 = []
            for i in self.x:
                x1.append(i[::-1])
            self.x = x1
            self.type = 'YF'

    def echo(self):
        print('tims:' + str(float(self.endAt) - float(self.beginAt)))
        #

        print('step:' + str(self.times))

        return self.data
        # if not self.canPlt:
        #     self.pltInit()
        # #
        # self.pltData()
        #
        # plt.pause(10000)
        # return self.resList

    def todo(self, step):
        if not self.doing:
            return
        if self.canPlt:
            self.pltData()
        self.times += 1

        if len(self.resList) == self.size:
            if self.checkX(True):
                self.endAt = time.time()
                self.doing = False
                self.data = self.resList.copy()
                # return
                return self.echo()
            return

        for i in range(0, len(self.tmpList[step])):
            self.resList.append(self.tmpList[step][i])

            if not self.checkX(False):
                self.resList.pop()
                continue
            else:
                self.todo(step + 1)

            self.resList.pop()

    def checkY(self, force):

        for k, line in enumerate(self.resList):
            if not checkLine(line, self.y[k], force):
                return False

        return True

    def checkX(self, force):
        xLine = []

        for i in range(0, self.size):
            t = ''
            for j in self.resList:
                t = t + str(j[i])
            xLine.append(t)

        for k, line in enumerate(xLine):
            if not checkLine(line, self.x[k], force):
                return False
        return True

    def pltData(self):
        if not self.resList:
            return
        data = self.resList.copy()
        paddingArr = repeat_string('0', self.size)
        data = pad_array_to_length(data, self.size, paddingArr)
        self.showPlt(data)

    def showPlt(self, data):
        print(data)
        plt.cla()

        for k1, i in enumerate(data):
            for k2, j in enumerate(i):
                if j == '1':
                    rect = plt.Rectangle((k2, self.size - 1 - k1), 0.95, 0.95)
                    self.ax.add_patch(rect)

        self.fig.canvas.draw()  # 重绘图像
        plt.xlim(0, self.size)
        plt.ylim(0, self.size)
        plt.xticks()
        plt.yticks()

        plt.pause(0.01)
